/*******************************************************************************
 * @file Copyright 2009 The CREATE Lab at CMU
 * 
 *       This file is part of JubJub, an open source project.
 *       http://code.google.com/p/jubjub/
 * 
 *       Redistribution and use in source and binary forms, with or without
 *       modification, are permitted provided that the following conditions are
 *       met:
 * 
 *       Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 * 
 *       Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 * 
 *       Neither the name of Carnegie Mellon nor the names of its contributors
 *       may be used to endorse or promote products derived from this software
 *       without specific prior written permission.
 * 
 *       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *       "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *       LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *       PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *       HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *       SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *       LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *       DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *       THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *       (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *       OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/

package edu.cmu.ri.createlab.jj.blocks;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import edu.cmu.ri.createlab.jj.JubJub.EmptyStringException;
import edu.cmu.ri.createlab.jj.blocks.BlockDefs.*;
import edu.cmu.ri.createlab.jj.visitors.*;
import edu.cmu.ri.createlab.jj.projects.*;

/**
 * 
 * @author Erik Pasternak
 *
 * The CodeBlock class is the core of the environment. It allows an arbitrary
 * piece of code with an arbitrary number of inputs and outputs to be stored
 * and used. Technically, all the necessary bits could be made from CodeBlocks,
 * but it would be a messy solution (you'd have to have a block just to close '}').
 * 
 * The main purpose of CodeBlock is to allow user created blocks to be added to the
 * environment. While all CodeBlocks behave the same way in the environment,
 * internally they are divided into INLINE and METHOD style blocks. METHOD style
 * blocks have no or one return and can therefore be generated as a function/method
 * when compiled to Java. INLINE style blocks have more than one return and must be
 * copied and pasted wherever they are used.
 */
public class CodeBlock implements BlockInterface, CallableBlockInterface
{
   /**
    * \defgroup BlockVars These variables are common to all BlockInterface types.
    */
   /*@{*/

   ///The name given to this block. CodeBlock and BlockBlock types should have unique names
   private String name;
   ///The JJClass which these blocks belong to and where they will be written to
   ///when output as code/xml
   private JJClass classOwner;
   ///What type of block this is from the list of BlockTypes
   private BlockTypes type;
   ///A unique ID for this block
   private int id;
   ///A list of RefBlock instances that reference this block.
   private List<RefBlock> refs;
   ///Whether this block is still valid or not
   private boolean valid;
   ///comment for this block
   private String comment;
   ///Whether it has an error or not
   private boolean error;
   
   /*@}*/
   
   /**
    * \defgroup CallableVars These variables are common to CodeBlocks, BlockBlocks, and VarBlocks.
    */
   /*@{*/
   ///This is a list of the access keywords that can go in front of a definition.
   ///So far this includes private, public, static, final, and protected. Up to
   ///3 access types can be included (ex. "public static final"). This list is
   ///defined in AccessTypes
   private AccessTypes[] access;
   ///This is to provide easy boolean access to the access types for quick lookup.
   ///The order is PUBLIC, PRIVATE, PROTECTED, FINAL, STATIC and should be referenced
   ///by calling BlockDefs.AccessTypes.TYPE.getIndex
   private boolean[] isAccess = {false, false, false, false, false};
   
   ///The name used when calling/defining this block in code.
   private String callName;
   /*@}*/
   
   /**
    * \defgroup CodeVars These variables are common to CodeBlock and BlockBlock types.
    */
   /*@{*/
   
   ///This determines whether a block is coded using an inline style or a method
   ///call, defined in CallTypes.
   private CallTypes callType;
   ///A list of the parameters passed into the block in VarBlock format.
   private List<VarBlock> params;
   ///A list of the returns passed out of the block in VarBlock format.
   private List<VarBlock> returns;
   ///A string with the full package or object name so that methods can be called explicitly.
   ///This should end with a '.' and is mainly for use with external code and objects, such
   ///as built in Java functions (eg. System.out.println).
   ///Two examples of prefixes would be "System.out." and "myFinch."
   private String prefix;
   ///Whether or not this block is a constructor
   private boolean constructor;
   
   ///swapNames is a temporary list of names to replace variables with.
   ///It should be set by the visitor whenever it processes a reference to this
   ///block and the names here will be used to replace variable names for that
   ///instance. TaggedCodePieces that reference a variable will contain the index
   ///of their variable, which should be in the order of the params then returns lists.
   private String[] swapNames;
   
   /*@}*/
   
   ///This is a list of Strings of code and variables to make writing out code
   ///easier where each element is a TaggedCodePiece.
   private List<TaggedCodePiece> taggedCode;
   
   
   /**
    * 
    * @param name A unique block name for this block.
    * @param owner Which JJClass it belongs to
    * @param ID A globally unique identifier
    * @throws EmptyStringException
    * 
    * Creates a CodeBlock without any access types.
    * 
    *  This creates a new CodeBlock without AccessTypes and sets most of its
    *  internal lists to null, meaning they still have to be set by the creating
    *  piece of code. params, returns, and taggedCode all have to be created
    *  externally. refs starts as an empty list that references can be added to. 
    */
   public CodeBlock(String name, JJClass owner, int ID) 
      throws Exception
   {
      this.setName(name);
      this.valid = true;
      this.classOwner = owner;
      this.id = ID;
      this.type = BlockTypes.CODE;
      this.callType = CallTypes.METHOD;
      this.access = null;
      this.params = new LinkedList<VarBlock>();
      this.returns = new LinkedList<VarBlock>();
      this.taggedCode = null;
      this.refs = new LinkedList<RefBlock>();
      this.prefix = null;
      this.comment = "";
   }
   
   /**
    * 
    * @param name A unique block name for this block.
    * @param owner Which JJClass it belongs to
    * @param ID A globally unique identifier
    * @param callType Whether this block is inline or method style
    * @throws EmptyStringException
    * 
    * Creates a CodeBlock without any access types.
    * 
    *  This creates a new CodeBlock without AccessTypes and sets most of its
    *  internal lists to null, meaning they still have to be set by the creating
    *  piece of code. params, returns, and taggedCode all have to be created
    *  externally. refs starts as an empty list that references can be added to. 
    */
   public CodeBlock(String name, JJClass owner, int ID, CallTypes callType) 
      throws Exception
   {
      this.setName(name);
      this.valid = true;
      this.classOwner = owner;
      this.id = ID;
      this.type = BlockTypes.CODE;
      this.callType = callType;
      this.access = null;
      this.params = new LinkedList<VarBlock>();
      this.returns = new LinkedList<VarBlock>();
      this.taggedCode = null;
      this.refs = new LinkedList<RefBlock>();
      this.prefix = null;
      this.comment = "";
   }
   
   /**
    * 
    * @param name A unique block name for this block.
    * @param owner Which JJClass it belongs to
    * @param ID A globally unique identifier
    * @param access The AccessTypes keywords that prepend the definition
    * @throws EmptyStringException
    * @throws BlockException 
    * 
    * Creates a CodeBlock with AccessTypes.
    * 
    *  This creates a new CodeBlock with the given access and sets most of its
    *  internal lists to null, meaning they still have to be set by the creating
    *  piece of code. params, returns, and taggedCode all have to be created
    *  externally. refs starts as an empty list that references can be added to.
    *  access should be a unique instance created for this instance.
    *
    */
   public CodeBlock(String name, JJClass owner, int ID, AccessTypes[] access)
      throws Exception
   {
      this.setName(name);
      this.valid = true;
      this.classOwner = owner;
      this.id = ID;
      this.type = BlockTypes.CODE;
      this.callType = CallTypes.METHOD;
      this.setAccess(access);
      this.params = new LinkedList<VarBlock>();
      this.returns = new LinkedList<VarBlock>();
      this.taggedCode = null;
      this.refs = new LinkedList<RefBlock>();
      this.prefix = null;
      this.comment = "";
   }
   
   /**
    * 
    * @param name A unique block name for this block.
    * @param owner Which class it belongs to
    * @param ID A globally unique identifier
    * @param access The access keywords that prepend the definition
    * @param params The inputs for this piece of code
    * @param returns The outputs for this piece of code
    * @throws EmptyStringException
    * @throws BlockException 
    * 
    * Creates a CodeBlock with specified AccessTypes and VarBlock variables.
    * 
    *  This creates a new CodeBlock with the given access and inputs/outpus.
    *  params, returns, and taggedCode all have to be created
    *  externally. refs starts as an empty list that references can be added to.
    *  List inputs should be unique instances created for this instance.
    *
    */
   public CodeBlock(String name, JJClass owner, int ID, AccessTypes[] access, 
         LinkedList<VarBlock> params, LinkedList<VarBlock> returns)
         throws Exception
   {
      ///If you try to set a block to INLINE and it has access types this
      ///is an error. INLINE is defined as a block with more than 1 return.
      if((returns != null && returns.size() > 1) && access != null)
      {
         throw new BlockException("Block cannot have multiple returns and have access types");
      }
      this.setName(name);
      this.valid = true;
      this.classOwner = owner;
      this.id = ID;
      this.type = BlockTypes.CODE;
      ///If this can be created as a callable METHOD do so, otherwise make it an
      ///INLINE block
      if(returns == null || returns.size() <= 1) this.callType = CallTypes.METHOD;
      else this.callType = CallTypes.INLINE;
      this.setAccess(access);
      this.params = new LinkedList<VarBlock>();
      this.returns = new LinkedList<VarBlock>();
      this.setParams(params);
      this.setReturns(returns);
      this.taggedCode = null;
      this.refs = new LinkedList<RefBlock>();
      this.prefix = null;
      this.comment = "";
   }
   
   /**
    * 
    * @param name A unique block name for this block.
    * @param owner Which class it belongs to
    * @param ID A globally unique identifier
    * @param access The access keywords that prepend the definition
    * @param params The inputs for this piece of code
    * @param returns The outputs for this piece of code
    * @param prefix The full package name for this method ending in '.'
    * @throws EmptyStringException
    * @throws BlockException 
    * 
    * Creates a CodeBlock with specified AccessTypes and VarBlock variables.
    * 
    *  This creates a new CodeBlock with the given access and inputs/outpus.
    *  params, returns, and taggedCode all have to be created
    *  externally. refs starts as an empty list that references can be added to.
    *  List inputs should be unique instances created for this instance.
    *
    */
   public CodeBlock(String name, JJClass owner, int ID, AccessTypes[] access, 
         LinkedList<VarBlock> params, LinkedList<VarBlock> returns, String prefix)
         throws Exception
   {
      ///If you try to set a block to INLINE and it has access types this
      ///is an error. INLINE is defined as a block with more than 1 return.
      if((returns != null && returns.size() > 1) && access != null)
      {
         throw new BlockException("Block cannot have multiple returns and have access types");
      }
      this.setName(name);
      this.valid = true;
      this.classOwner = owner;
      this.id = ID;
      this.type = BlockTypes.CODE;
      ///If this can be created as a callable METHOD do so, otherwise make it an
      ///INLINE block
      if(returns == null || returns.size() <= 1) this.callType = CallTypes.METHOD;
      else this.callType = CallTypes.INLINE;
      this.setAccess(access);
      this.params = new LinkedList<VarBlock>();
      this.returns = new LinkedList<VarBlock>();
      this.setParams(params);
      this.setReturns(returns);
      this.taggedCode = null;
      this.refs = new LinkedList<RefBlock>();
      this.prefix = prefix;
      this.comment = "";
   }

   /**
    * \defgroup BlockMethods These methods are common to all blocks.
    */
   /*@{*/

   ///Sets the comment for this block
   public void setComment(String comment)
   {
      this.comment = comment;
   }
   
   ///Gets the comment for this block
   public String getComment()
   {
      return comment;
   }
   
   ///Return whether this block is still valid or if it is deleted pending
   ///removal of all its refs.
   public boolean isValid()
   {
      return valid;
   }
   
   ///Return whether this block currently has an error
   public boolean hasError()
   {
      return error;
   }
   
   ///check the error state for this block
   public void checkError()
   {
      Iterator<VarBlock> vIt = this.params.iterator();
      while(vIt.hasNext())
      {
         if(vIt.next().hasError())
         {
            this.error = true;
            if(this.classOwner != null)
               this.classOwner.checkError();
            return;
         }
      }
      vIt = this.returns.iterator();
      while(vIt.hasNext())
      {
         if(vIt.next().hasError())
         {
            this.error = true;
            if(this.classOwner != null)
               this.classOwner.checkError();
            return;
         }
      }
      if(this.error)
      {
         this.error = false;
         if(this.classOwner != null)
            this.classOwner.checkError();
      }
   }
   
   ///Sets this block to not Valid and updates all its refs
   public void deleteBlock()
   {
      valid = false;
      this.updateRefs();
   }
   
   ///Sets this block to Valid and updates all its refs
   public void undeleteBlock()
   {
      valid = true;
      this.updateRefs();
   }

   ///registers the block with its current class
   public void register()
      throws BlockException
   {
      if(this.classOwner != null)
      {
         if(this.callType == CallTypes.INLINE)
            this.classOwner.addInlineBlock(this);
         else this.classOwner.addMethodBlock(this);
      }
   }
   
   ///unregisters the block from its class.
   public void unregister()
   {
      if(this.classOwner != null)
      {
         if(this.callType == CallTypes.INLINE)
            this.classOwner.removeInlineBlock(this);
         else this.classOwner.removeMethodBlock(this);
      }
      this.setOwner(null);
   }
   
   ///This makes it easier for the garbage collector to remove this block
   ///by ensuring all the references it contains are removed.
   public void destroyBlock()
   {
      ///Remove all references to everything
      Iterator<VarBlock> it;
      ///It should never be the case that params/returns is null, but we'll
      ///leave this in for now.
      if(this.params != null)
      {
         it = this.params.iterator();
         while(it.hasNext())
         {
            it.next().destroyBlock();
         }
         this.params.clear();
      }
      if(this.returns != null)
      {
         it = this.returns.iterator();
         while(it.hasNext())
         {
            it.next().destroyBlock();
         }
         this.returns.clear();
      }
      Iterator<RefBlock> rIt = this.refs.iterator();
      while(rIt.hasNext())
      {
         rIt.next().clearBlock();
      }
      this.refs.clear();
      //this.setOwner(null);
            
   }
   
   ///Accepts a BlockVisitorInterface and visits itself
   public BVReturn accept(BlockVisitorInterface bv)
   {
      bv.visit(this);
      return null;
   }
   
   ///returns the JJClass that owns this block
   
   public JJClass getOwner()
   {
      return classOwner;
   }

   ///returns the id for this block
   
   public int getID()
   {
      return id;
   }

   ///returns the name of this block
   
   public String getName()
   {
      return name;
   }

   ///returns the BlockTypes type of this block
   
   public BlockTypes getType()
   {
      return type;
   }

   ///sets the JJClass that owns this block
   
   public void setOwner(JJClass owner)
   {
      this.classOwner = owner;
      
   }

   ///sets the name of this block as well as its callName.
   
   public void setName(String name) throws EmptyStringException
   {
      ///If the name is of 0 length we've made a mistake and need to throw
      ///an exception.
      if(name.length() == 0) 
      {
         throw new EmptyStringException("Empty string name");
      }
      this.name = name;
      ///The callname should be the same as the name with some changes to make it
      ///Java friendly
      this.callName = name.replaceAll("[^a-z&&[^A-Z]&&[^0-9]&&[^_]]+", "_");
      if(!(this.callName.substring(0, 1).matches("[a-zA-z]")))
      {
         this.callName = "a" + this.callName;
      }
   }
   
   ///Adds a RefBlock to the list of references
   
   public void addRef(RefBlock ref)
   {
      if(refs.contains(ref)) return;
      refs.add(ref);
   }

   ///Removes the given RefBlock from the list of references
   
   public void remRef(RefBlock ref)
   {
      refs.remove(ref);
   }
   
   ///Returns a list of RefBlock types that reference this block
   public List<RefBlock> getRefs()
   {
      return refs;
   }

   ///Updates all the RefBlock references to this block
   
   public void updateRefs()
   {
      Iterator<RefBlock> it = refs.iterator();
      while(it.hasNext())
      {
         it.next().update();
      }
   }
   
   /*@}*/
   
   /**
    * \defgroup InstanceBlocks These methods are common to CodeBlock, BlockBlock, and VarBlock types.
    */
   /*@{*/
   
   ///Returns the list of AccessTypes keywords, may be null. Access should be null for
   ///INLINE type CodeBlocks and BlockBlocks
   public AccessTypes[] getAccess()
   {
      return access;
   }

   /**
    * @param access
    * @throws BlockException
    * 
    * Sets the list of AccessTypes keywords. May be null.
    * This will also check to ensure access types aren't being set for an INLINE
    * style block and that only one of public/private/protected is set. It will
    * also set the appropriate boolean flags for quick access to access settings.
    */
   public void setAccess(AccessTypes[] access) throws Exception
   {
      AccessTypes[] tempAccess = this.access;
      boolean[] tempIsAccess = this.isAccess.clone();
      ///A block becomes INLINE if it has more than one return, and since we
      ///can't create methods with more than one return it must be INLINE if
      ///it has multiple returns and vice versa.
      if(this.callType == CallTypes.INLINE && access != null)
      {
         throw new BlockException("Block cannot have multiple returns and have access types.");
      }
      ///Set the access keywords
      this.access = access;
      ///Set the boolean array to false to start
      for(int i = 0; i < this.isAccess.length; i++)
      {
         this.isAccess[i] = false;
      }
      ///Now set true any access keywords we added 
      if(access != null)
      {
         for(int i = 0; i < access.length; i++)
         {
            if(access[i] != null) this.isAccess[access[i].getIndex()] = true;
         }
         ///You can only have one of the three visibility access types
         if((this.isAccess[AccessTypes.PUBLIC.getIndex()] && this.isAccess[AccessTypes.PRIVATE.getIndex()])
            || (this.isAccess[AccessTypes.PUBLIC.getIndex()] && this.isAccess[AccessTypes.PROTECTED.getIndex()])
            || (this.isAccess[AccessTypes.PRIVATE.getIndex()] && this.isAccess[AccessTypes.PROTECTED.getIndex()]))
         {
            ///so if we improperly set one of these undo changes and throw an exception
            this.access = tempAccess;
            this.isAccess = tempIsAccess;
            throw new BlockException("Can only have one of the following access types public/private/protected.");
         }
      }
      return;
   }
   
   ///returns whether or not this has the public keyword
   public boolean isPublic()
   {
      return isAccess[AccessTypes.PUBLIC.getIndex()];
   }

   ///returns whether or not this has the private keyword
   public boolean isPrivate()
   {
      return isAccess[AccessTypes.PRIVATE.getIndex()];
   }

   ///returns whether or not this has the protected keyword
   public boolean isProtected()
   {
      return isAccess[AccessTypes.PROTECTED.getIndex()];
   }

   ///returns whether or not this has the static keyword
   public boolean isStatic()
   {
      return isAccess[AccessTypes.STATIC.getIndex()];
   }

   ///returns whether or not this has the final keyword
   public boolean isFinal()
   {
      return isAccess[AccessTypes.FINAL.getIndex()];
   }
   
   /*@}*/
   
   
   /**
    * \defgroup CodeMethods These methods are common to CodeBlocks and BlockBlocks.
    */
   /*@{*/
   
   ///Returns the prefix for this CodeBlock
   public String getPrefix()
   {
      return prefix;
   }
   
   ///Sets the prefix for this CodeBlock
   public void setPrefix(String s)
   {
      prefix = s;
   }
   
   //Sets whether this block is a constructor or not.
   public void setConstructor(boolean constructor)
      throws Exception
   {
      if(constructor && !isPublic() && returns != null)
      {
         throw new BlockException("Constructors must be public and have no returns.");
      }
      this.constructor = constructor;
   }

   public boolean isConstructor()
   {
      return constructor;
   }

   ///returns the callName for this block
   public String getCallName()
   {
      return callName;
   }
   
   ///Checks the given string against the callName for this block
   public boolean isSameCallName(String name)
   {
      return this.callName.equals(name);
   }
   
   ///Returns the type of call, either INLINE or METHOD.
   ///Defined in CallTypes
   public CallTypes getCallType()
   {
      return callType;
   }
   
 ///returns the list of parameters as a VarBlock list
   public List<VarBlock> getParams()
   {
      return params;
   }
   
   ///returns the number of params
   public int getNumParams()
   {
      return params.size();
   }
   
   ///sets the list of paramaters. This should only be called at creation.
   private void setParams(List<VarBlock> params)
   {
      if(params != null)
      {
         Iterator<VarBlock> it = params.iterator();
         while(it.hasNext())
            this.addParam(it.next());
      }
   }
   
   ///Adds a parameter to its list
   public void addParam(VarBlock param)
   {
      this.params.add(param);
   }
   
   ///Adds a parameter to its list
   public void addParam(VarBlock param, int index)
   {
      this.params.add(index, param);
   }
   
   
   ///sets the list of returns, throws an exception if there is more than
   ///a single return and the block is a METHOD type.
   private void setReturns(List<VarBlock> returns)
      throws BlockException
   {
      if(returns != null)
      {
         if(returns.size() > 1 && this.callType != CallTypes.INLINE)
         {
            throw new BlockException("Method Blocks cannot have multiple returns");
         }
         Iterator<VarBlock> it = returns.iterator();
         while(it.hasNext())
            this.addReturn(it.next());
      }
   }
   
   ///Adds the given variable as a return
   ///It's up to the editor to decide if more than one return is acceptable
   public void addReturn(VarBlock ret)
   {
      returns.add(ret);
   }
   
   ///Adds the given variable as a return at the given index
   ///It's up to the editor to decide if more than one return is acceptable
   public void addReturn(VarBlock ret, int index)
   {
      returns.add(index, ret);
   }
   
   ///returns the list of returns as a VarBlock list
   public List<VarBlock> getReturns()
   {
      return returns;
   }
   
   ///returns the number of returns
   public int getNumReturns()
   {
      return returns.size();
   }
   
   ///Sets callType to the specified CallTypes type for the function.
   ///If the type is INLINE this will set the access keywords to null.
   public void setCallType(CallTypes type)
   {
      ///if we set this block to be inline remove its access types
      if(type == CallTypes.INLINE && this.access != null)
      {
         this.access = null;
      }
      this.callType = type;
   }

   ///sets the names to be used when outputting the code when different
   ///variable names should be swapped in (mainly INLINE types).
   public void setSwaps(String[] names)
   {
      swapNames = names;
   }
   
   ///Returns the swapNames that are currently in use.
   public String[] getSwaps()
   {
      return swapNames;
   }

   /*@}*/
   
   ///returns the tagged code for this block as a TaggedCodePiece List.
   public List<TaggedCodePiece> getTaggedCode()
   {
      return taggedCode;
   }
   
   ///sets the tagged code for this block
   public void setTaggedCode(List<TaggedCodePiece> tc)
   {
	   this.taggedCode = tc;
   }
   ///Converts a CodeBlock into a readable format and returns it as a string.
   public String toString()
   {
	   String s = "Type:" + type.toString();
	      s += " ID:" + id;
	      s += " Name:" + name;
	      if(prefix == null) s += " CallName:" + callName;
	      else s += " CallName:" + prefix + callName;
	      s += " CallType:" + callType;
	      s += " Owner:" + classOwner;
	      s += " Access:";
	      if(access != null)
	         for(int i = 0; i < access.length; i++)
	            s += access[i].toString() + " ";
	      s+= " NumRefs:" + refs.size();
	      s += "\nParams:";
	      if(params != null)
	    	  for(int i = 0; i < params.size(); i++)
	    		  s += params.get(i).getCallName() + ", ";
	      s += "\nReturns:";
	      if(returns != null)
	    	  for(int i = 0; i < returns.size(); i++)
	    		  s += returns.get(i).getCallName() + ", ";

	      if(taggedCode != null)
	      {
	    	  s += "\nCode:\"";
	    	  for(int i = 0; i < taggedCode.size(); i++)
	    		  s+= taggedCode.get(i).getContent();
	    	  s += "\"";
	      }
	      else
	      {
	    	  s += "\nExternal Code";
	      }
	      
	      return s;
   }
   
   ///Test function for CodeBlock. Creates a few CodeBlocks and prints out their contents.
   public static void main(String[] args)
   {
      ///Create an inline bit of code
      CodeBlock cb1, cb2, cb3, cb4;
      LinkedList<TaggedCodePiece> tc1 = new LinkedList<TaggedCodePiece>();
      tc1.add(new TaggedCodePiece("x",0));
      tc1.add(new TaggedCodePiece(" = "));
      tc1.add(new TaggedCodePiece("point",2));
      tc1.add(new TaggedCodePiece(".getX();\n"));
      tc1.add(new TaggedCodePiece("y",1));
      tc1.add(new TaggedCodePiece(" = "));
      tc1.add(new TaggedCodePiece("point",2));
      tc1.add(new TaggedCodePiece(".getY();\n"));
      ///Create a piece of code that can be called
      LinkedList<TaggedCodePiece> tc2 = new LinkedList<TaggedCodePiece>();
      tc2.add(new TaggedCodePiece("System.out.println("));
      tc2.add(new TaggedCodePiece("s",0));
      tc2.add(new TaggedCodePiece(");\n"));
      LinkedList<VarBlock> p1 = new LinkedList<VarBlock>();
      LinkedList<VarBlock> r1 = new LinkedList<VarBlock>();
      LinkedList<VarBlock> p2 = new LinkedList<VarBlock>();
      LinkedList<VarBlock> r2 = null;
      try
      {
    	  p1.add(new VarBlock("point", null, 1, VarTypes.INT));
    	  r1.add(new VarBlock("x", null, 1, VarTypes.INT));
    	  r1.add(new VarBlock("y", null, 1, VarTypes.INT));
    	  p2.add(new VarBlock("s", null, 1, VarTypes.INT));
    	  cb1 = new CodeBlock("Code __Block 1^%", null, 1, null, p1, r1);
    	  cb2 = new CodeBlock("println", null, 2, null, p2, r2, "System.out.");
    	  cb3 = new CodeBlock("println", null, 3, null, p2, r2);
    	  cb4 = new CodeBlock("emptyMethod",null,4,null,null,null);
    	  cb1.setTaggedCode(tc1);
    	  cb3.setTaggedCode(tc2);
    	  cb4.setTaggedCode(new LinkedList<TaggedCodePiece>());
    	  
    	  RefBlock rb[] = {new RefBlock(5,cb2), new RefBlock(6,cb3), new RefBlock(7,cb4)};

    	  cb1.addRef(rb[0]);
    	  cb1.addRef(rb[1]);
    	  cb1.addRef(rb[2]);
    	  cb1.addRef(rb[1]);
    	  cb1.remRef(rb[0]);
    	  AccessTypes[] cb3Access = {AccessTypes.FINAL, AccessTypes.STATIC}; 
    	  cb3.setAccess(cb3Access);
    	 cb3Access[0] = AccessTypes.PUBLIC; 
       cb3.setAccess(cb3Access);
      }
      catch(Exception e)
      {
    	  System.err.println(e.getMessage());
    	  return;
      }
      
      System.out.println(cb1.toString() + "\n");
      System.out.println(cb2.toString() + "\n");
      System.out.println(cb3.toString() + "\n");
      System.out.println(cb4);
      System.out.println(cb3.isFinal() + " " + cb3.isPublic());
      
      
   }

}
